home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 11 / CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso / cucd / programming / oberonv4 / source / system / pictures.mod (.txt) < prev    next >
Oberon Text  |  1996-06-19  |  33KB  |  842 lines

  1. Syntax10.Scn.Fnt
  2. ParcElems
  3. Alloc
  4. Syntax24b.Scn.Fnt
  5. StampElems
  6. Alloc
  7. 19 Jun 96
  8. Syntax10b.Scn.Fnt
  9. Syntax10i.Scn.Fnt
  10. Syntax20b.Scn.Fnt
  11. Syntax16b.Scn.Fnt
  12. (* AMIGA *)
  13. MODULE Pictures; (* cn, RD, OJ 
  14. IMPORT
  15.     SYSTEM,Amiga,Files,E:=AmigaExec,G:=AmigaGraphics,I:=AmigaIntuition,Kernel,L:=AmigaLayers, O:=Console;
  16. CONST
  17.     black*=0; white*=15;
  18.     replace*=0; (* The new graphical object completely replaces whatever was before in the destination area. *)
  19.     paint*=1; (* The new graphical object is added to whatever was before in the dertination area. *)
  20.     invert*=2; (* The new graphical object inverts whatever was before in the dertination area. The color specifies, which planes are affected (inverted) and which aren't *)
  21.     PictFileId*=  - 4093;
  22.     BitMapPtr=POINTER TO G.BitMap;
  23.     LayerPtr=POINTER TO G.Layer;
  24.     RastPortPtr=POINTER TO G.RastPort;
  25.     WindowPtr=POINTER TO I.Window;
  26.     ScreenPtr=POINTER TO I.Screen;
  27.     ColMem=ARRAY 256 OF RECORD r, g, b: CHAR END;
  28.     Pattern*=LONGINT;
  29.     Picture*=POINTER TO PictureDesc;
  30.     Notifier*=PROCEDURE (P: Picture; X, Y, W, H : INTEGER);
  31.     PictureDesc*=RECORD
  32.         width*,height*,depth*:INTEGER;
  33.         notify*:Notifier;
  34.         bitMap:G.BitMap; (* Used only in CreateLayer, FreeLayer; V<39*)
  35.         bitMapPtr:G.BitMapPtr; (* Used only in CreateLayer, FreeLayer; V>=39*)
  36.         layer:G.LayerPtr;
  37.         layerInfo: G.LayerInfoPtr; (* Used only in CreateLayer, FreeLayer *)
  38.         rp*: G.RastPortPtr;
  39.         pal: ColMem;
  40.         oldCol:INTEGER;
  41.         oldMode:INTEGER
  42.     END ;
  43.     Frame*=POINTER TO FrameDesc;
  44.     FrameMsg*=RECORD END;
  45.     Handler*=PROCEDURE (f: Frame; VAR msg: FrameMsg);
  46.     FrameDesc*=RECORD
  47.         dsc*, next*: Frame;
  48.         X*, Y*, W*, H*: INTEGER;
  49.         handle*: Handler
  50.     END;
  51.     PatternNode=POINTER TO RECORD
  52.         p: Amiga.PatternInfoPtr;
  53.         next: PatternNode
  54.     END;
  55.     dots*: Pattern;
  56.     ToPrint*: Picture;
  57.     rev: ARRAY 16 OF INTEGER;
  58.     defaultPicture:Picture;
  59.     nofCols, depthMask:INTEGER; (* depthMask:=nofCols-1 *)
  60.     patternRoot:PatternNode;
  61.     DispColBuffer: ColMem;
  62.     DrMode: ARRAY 3 OF SHORTINT;    (* conversion table, used in SetDrawMode *)        (*<<OJ*)
  63.     MinTerm: ARRAY 3 OF CHAR;    (* conversion table, used in CopyBlock *)
  64. PROCEDURE SetDisplayColor*(col, red, green, blue: INTEGER); (*col < 0: overlay color not supported on the Amiga*)
  65.     Set the RGB values for a screen color.
  66.     scr:ScreenPtr;
  67.     win: WindowPtr;
  68. BEGIN
  69.     IF Amiga.ModifyColors & (col<nofCols) & (col>=0) THEN
  70.         win := SYSTEM.VAL(WindowPtr, Amiga.window);
  71.         scr := SYSTEM.VAL(ScreenPtr, win.wScreen);
  72.         G.SetRGB32(
  73.             SYSTEM.VAL(G.ViewPortPtr,SYSTEM.ADR(scr.viewPort)),col+Amiga.ColorOffset,
  74.             SYSTEM.LSH(LONG(red),24),SYSTEM.LSH(LONG(green),24),SYSTEM.LSH(LONG(blue),24)
  75. END SetDisplayColor;
  76. PROCEDURE GetDisplayColor*(col: INTEGER; VAR red, green, blue: INTEGER);
  77.     Return the RGB values for a screen color.
  78.     rgbTable:RECORD r,g,b:LONGINT END;
  79.     scr:ScreenPtr;
  80.     win: WindowPtr;
  81. BEGIN
  82.     win := SYSTEM.VAL(WindowPtr, Amiga.window);
  83.     scr:=SYSTEM.VAL(ScreenPtr, win.wScreen);
  84.     G.GetRGB32(scr.viewPort.colorMap,col MOD nofCols,1,rgbTable);
  85.     red     := SHORT( SYSTEM.LSH(rgbTable.r,-24));
  86.     green := SHORT( SYSTEM.LSH(rgbTable.g,-24));
  87.     blue   := SHORT( SYSTEM.LSH(rgbTable.b,-24))
  88. END GetDisplayColor;
  89. PROCEDURE ColorsToScreen(m: ColMem);
  90.     Copy colors from ColMem to screen
  91.     VAR i: INTEGER;
  92. BEGIN
  93.     FOR i:=0 TO nofCols-1 DO
  94.         SetDisplayColor(i, ORD(m[i].r), ORD(m[i].g), ORD(m[i].b))
  95. END ColorsToScreen;
  96. PROCEDURE GetScreenColors(VAR m: ColMem);
  97.     Copy screen colors to ColMem
  98.     VAR i, r, g, b: INTEGER;
  99. BEGIN
  100.     FOR i:=0 TO nofCols-1 DO
  101.         GetDisplayColor(i, r, g, b);
  102.         m[i].r:=CHR(r); m[i].g:=CHR(g); m[i].b:=CHR(b)
  103. END GetScreenColors;
  104. PROCEDURE UseOberonColors*(p: Picture);
  105.     Store current screen colors to DispColBuffer and copy colors of Picture p to screen
  106. BEGIN
  107.     GetScreenColors(DispColBuffer);
  108.     ColorsToScreen(p.pal)
  109. END UseOberonColors;
  110. PROCEDURE UseBufferedColors*;
  111.     Copy colors from DispColBuffer to screen
  112. BEGIN
  113.     ColorsToScreen(DispColBuffer)
  114. END UseBufferedColors;
  115. PROCEDURE InitLayer(pic:Picture);
  116.     Precondition: pic has already initialized depth, width and height fields.
  117.     Creates bitmap and layer.
  118.         l: LayerPtr;
  119.         rp: RastPortPtr;
  120. BEGIN
  121.     rp:=SYSTEM.VAL(RastPortPtr, defaultPicture.rp);
  122.     pic.bitMapPtr:=G.AllocBitMap(pic.width, pic.height, Amiga.Depth, {}, rp.bitMap);
  123.     Amiga.Assert(pic.bitMapPtr#0,"Can't allocate BitMap");
  124.     pic.layerInfo:=L.NewLayerInfo();
  125.     Amiga.Assert(pic.layerInfo#0,"No layer info");
  126.     pic.layer:=L.CreateUpfrontLayer(
  127.         pic.layerInfo,pic.bitMapPtr,0,0,pic.width-1,pic.height-1,{G.layerSimple,G.layerBackdrop},0
  128.     IF pic.layer=0 THEN HALT(70) END;
  129.     l:=SYSTEM.VAL(LayerPtr,pic.layer);
  130.     pic.rp:=l.rp
  131. END InitLayer;
  132. PROCEDURE FreeLayer(pic:Picture);
  133.     Free layer and bitmap.
  134. BEGIN
  135.     IF pic.layer#0 THEN
  136.         ASSERT(L.DeleteLayer(pic.layer));
  137.         G.WaitBlit();
  138.         pic.layer:=0
  139.     END;
  140.     IF pic.layerInfo#0 THEN L.DisposeLayerInfo(pic.layerInfo); pic.layerInfo:=0 END;
  141.     G.FreeBitMap(pic.bitMapPtr);
  142.     pic.oldCol:=-1;
  143.     pic.oldMode:=-1;
  144.     pic.depth:=0;
  145.     pic.width:=0;
  146.     pic.height:=0
  147. END FreeLayer;
  148. PROCEDURE WindowToPicture*(window:I.WindowPtr; VAR pic:Picture);
  149.     Using this procedure you can create a picture which represents a windows
  150.     contents. This procedure is only intended for use by Display.
  151.     NOTE:
  152.         never reuse this picture in a Pictures.Create call!
  153.     bm:BitMapPtr;
  154.     i:INTEGER;
  155.     rp:RastPortPtr;
  156.     w:WindowPtr;
  157. BEGIN
  158.     w:=SYSTEM.VAL(WindowPtr,window);
  159.     NEW(pic);
  160.     pic.width:=w.width-w.borderLeft-w.borderRight;
  161.     pic.height:=w.height-w.borderTop-w.borderBottom;
  162.     pic.rp:=w.rPort;
  163.     rp:=SYSTEM.VAL(RastPortPtr,w.rPort);
  164.     bm:=SYSTEM.VAL(BitMapPtr,rp.bitMap);
  165.     pic.depth:=bm.depth;
  166.     pic.notify:=NIL;
  167.     FOR i:=0 TO pic.depth-1 DO
  168.         pic.bitMap.planes[i]:=0; (* Used only in CreateLayer, FreeLayer *)
  169.     END;
  170.     pic.layer:=w.wLayer;
  171.     pic.layerInfo:=0; (* Used only in CreateLayer, FreeLayer *)
  172.     pic.oldCol:=-1;
  173.     pic.oldMode:=-1;
  174.     defaultPicture:=pic; (* Remember Oberon screen for DisplayBlock. I hate Pictures/Display! cn *)
  175. END WindowToPicture;
  176. PROCEDURE Finalize(obj: SYSTEM.PTR);
  177. BEGIN
  178.     FreeLayer(SYSTEM.VAL(Picture,obj))
  179. END Finalize;
  180. PROCEDURE Address*(P: Picture): LONGINT;
  181.     Not supported at the Amiga, returns 0
  182.     This PROCEDURE has a side effect. It stores the Picture in ToPrint.
  183.     It is used for Printing Pictures.
  184. BEGIN
  185.     ToPrint:=P;
  186.     RETURN 0
  187. END Address;
  188. PROCEDURE SetDrawMode(pic:Picture; col, mode: INTEGER); (* Faster and Shorter << OJ *)
  189.     Ckeck old DrawModes (Mode, Color) and set new, if changed
  190.     Every PROCEDURE drawing to a Picture has to call this
  191.     WriteMsk has to be changed if mode changes to invert or (in mode invert) the color changes
  192. BEGIN
  193.     IF pic.oldMode # mode THEN
  194.         pic.oldMode := mode;  G.SetDrMd(pic.rp, DrMode[mode]);
  195.         pic.oldCol := col;
  196.         col:=col MOD nofCols;
  197.         IF mode=invert THEN
  198.             G.SetWriteMask(pic.rp, col)
  199.         ELSE
  200.             G.SetWriteMask(pic.rp,depthMask);
  201.             G.SetAPen(pic.rp, col+Amiga.ColorOffset)
  202.         END
  203.     ELSIF pic.oldCol # col THEN
  204.         pic.oldCol := col;
  205.         col:=col MOD nofCols;
  206.         IF mode=invert THEN
  207.             G.SetWriteMask(pic.rp, col)
  208.         ELSE
  209.             G.SetAPen(pic.rp, col+Amiga.ColorOffset)
  210.         END
  211. END SetDrawMode;
  212. PROCEDURE CopyBlock*(sP, dP: Picture; SX, SY, W, H, DX, DY, mode: INTEGER);
  213.     Copy a rectangular area within the display to another place. This procedure assumes, that any single
  214.     area does not cross the boundary between primary and secondary screen.
  215. BEGIN
  216.     IF (W <= 0) OR (H <= 0) THEN RETURN END;
  217.     SetDrawMode(dP, dP.oldCol, mode); (* only to set mask *)
  218.     G.ClipBlit(sP.rp, SX, sP.height-SY(*-1*)-H,
  219.                     dP.rp, DX, dP.height-DY(*-1*)-H, W, H, MinTerm[mode])        (*<<OJ*)
  220. END CopyBlock;
  221. PROCEDURE CopyBlockC*(sP, dP:Picture; f: Frame; SX, SY, W, H, DX, DY, mode: INTEGER);
  222.     As CopyBlock, but the destination area is clipped against the Frame boundary.
  223.     VAR dx, dy: INTEGER;
  224. BEGIN
  225.     IF (W <= 0) OR (H <= 0) THEN RETURN END;
  226.     dx := f.X-DX;
  227.     IF dx > 0 THEN INC(SX, dx); DX := f.X; DEC(W, dx) END;
  228.     dx := DX+W-(f.X+f.W);
  229.     IF dx > 0 THEN DEC(W, dx) END;
  230.     dy := f.Y-DY;
  231.     IF dy > 0 THEN INC(SY, dy); DY := f.Y; DEC(H, dy) END;
  232.     dy := DY+H-(f.Y+f.H);
  233.     IF dy > 0 THEN DEC(H, dy) END;
  234.     IF (W > 0) & (H > 0) THEN CopyBlock(sP, dP, SX, SY, W, H, DX, DY, mode) END
  235. END CopyBlockC;
  236. PROCEDURE CopyPattern*(pic:Picture; col: INTEGER; pat: Pattern; X, Y, mode: INTEGER);
  237.     Copy a pattern to the specified location.
  238.     p: Amiga.PatternInfoPtr;
  239.     wordStart:LONGINT;
  240.     bitOffset:INTEGER;
  241.     w, h:INTEGER;
  242. BEGIN
  243.     p := SYSTEM.VAL( Amiga.PatternInfoPtr, pat); w := p.w; h := p.h;
  244.     IF (w > 0) & (h > 0) THEN
  245.         SetDrawMode(pic, col, mode);
  246.         wordStart:=p.data+p.offset DIV 8;
  247.         bitOffset:=SHORT(p.offset MOD 8);
  248.         IF ODD(wordStart) THEN
  249.             DEC(wordStart);
  250.             INC(bitOffset,8)
  251.         END;
  252.         G.BltTemplate(wordStart, bitOffset, p.modulo, pic.rp, X, pic.height-Y-h, w, h)
  253. END CopyPattern;
  254. PROCEDURE CopyPatternC*(pic:Picture; f: Frame; col: INTEGER; pat: Pattern; X, Y, mode: INTEGER);
  255.     As CopyPattern, but clips the pattern against the frame boundary.
  256.     dx, sx, dy, sy, w, h: INTEGER; p: Amiga.PatternInfoPtr;
  257.     PROCEDURE copyPattern(pic:Picture; col: INTEGER; pat: Pattern; X, Y, dx, dy, w, h, mode: INTEGER);
  258.         Routine used by CopyPattern and CopyPatternC. It will copy a pattern into the designated destination
  259.         area. This routines is able to extract an arbitrary rectangular region from the origin pattern.
  260.         p: Amiga.PatternInfoPtr;
  261.         wordStart, bitIn:LONGINT;
  262.         bitOffset:INTEGER;
  263.     BEGIN
  264.         p := SYSTEM.VAL( Amiga.PatternInfoPtr, pat);
  265.         w := p.w+w; h := p.h+h;
  266.         IF (w > 0) & (h > 0) THEN
  267.             SetDrawMode(pic, col, mode);
  268.             bitIn:=dx+p.offset;
  269.             wordStart:=p.data+dy*p.modulo+bitIn DIV 8;
  270.             bitOffset:=SHORT(bitIn MOD 8);
  271.             IF ODD(wordStart) THEN
  272.                 DEC(wordStart);
  273.                 INC(bitOffset,8)
  274.             END;
  275.             G.BltTemplate(wordStart, bitOffset, p.modulo, pic.rp, X, pic.height-Y-h, w, h)
  276.         END
  277.     END copyPattern;
  278. BEGIN
  279.     p := SYSTEM.VAL(Amiga.PatternInfoPtr, pat);
  280.     dx := f.X-X; sx := 0; sy := 0; w := p.w; h := p.h;
  281.     IF dx > 0 THEN sx := dx; X := f.X; DEC(w, dx) END;
  282.     dx := X+w-(f.X+f.W);
  283.     IF dx > 0 THEN DEC(w, dx) END;
  284.     dy := f.Y-Y;
  285.     IF dy > 0 THEN Y := f.Y; DEC(h, dy) END;    (* don't adjust sy offset here. *)
  286.     dy := Y+h-(f.Y+f.H);
  287.     IF dy > 0 THEN sy := dy; DEC(h, dy) END;    (* adjust sy offset here, because of Amiga display model *)
  288.     copyPattern(pic, col, pat, X, Y, sx, sy, w-p.w, h-p.h, mode)
  289. END CopyPatternC;
  290. PROCEDURE Dot*(pic:Picture; col: INTEGER; X, Y, mode: INTEGER);
  291.     Change a single pixel.
  292. BEGIN
  293.     SetDrawMode(pic, col, mode);
  294.     G.WritePixel(pic.rp, X, pic.height-Y-1)
  295. END Dot;
  296. PROCEDURE DotC*(pic:Picture; f: Frame; col: INTEGER; X, Y, mode: INTEGER);
  297.      As Dot, but the the pixel is only written, if contained within the frame boundary.
  298. BEGIN
  299.     IF (X >= f.X) & (X < f.X+f.W) & (Y >= f.Y) & (Y < f.Y+f.H) THEN Dot(pic, col, X, Y, mode) END
  300. END DotC;
  301. PROCEDURE Get*(P: Picture; X, Y: INTEGER): INTEGER;
  302.     Returns color of pixel at pos (X,Y)
  303.     col:INTEGER;
  304. BEGIN
  305.     IF (X<0) OR (X>=P.width) OR (Y<0) OR (Y>=P.height) THEN RETURN black END ;
  306.     IF P.oldMode=invert THEN
  307.         P.oldMode:=replace;
  308.         G.SetWriteMask(P.rp, depthMask);
  309.         G.SetDrMd( P.rp, replace)
  310.     END;
  311.     col:=G.ReadPixel(P.rp,X,P.height-Y-1);
  312.     RETURN col-Amiga.ColorOffset
  313. END Get;
  314. PROCEDURE Copy*(sP, dP: Picture; xs, ys, ws, hs, xd, yd, wd, hd, mode: INTEGER);
  315.     Used to produce a scaled copy of a Picture
  316.     VAR hx, hy, wd2, ws2: LONGINT; dx, dy, xso, xdo: INTEGER;
  317. BEGIN
  318.     dy:=yd + hd;  dx:=xd + wd; xso:=xs; xdo:=xd; wd2:=2*wd; ws2:=2*ws;
  319.     hy:=2*hs - hd;
  320.     WHILE yd < dy DO
  321.         hx:=2*ws - wd; xd:=xdo; xs:=xso;
  322.         WHILE xd < dx DO
  323.             Dot(dP, Get(sP, xs, ys), xd, yd, mode);
  324.             WHILE hx > 0 DO INC(xs); DEC(hx, wd2) END;
  325.             INC(xd); INC(hx, ws2)
  326.         END ;
  327.         WHILE hy > 0 DO INC(ys); hy:=hy - 2*hd END;
  328.         INC(yd); hy:=hy + 2*hs
  329. END Copy;
  330. PROCEDURE ReplConst*(pic: Picture; col, X, Y, W, H, mode: INTEGER);
  331.     Generate a rectangle with the specified color and paint mode.
  332. BEGIN
  333.     IF (W <= 0) OR (H <= 0) THEN RETURN END;
  334.     SetDrawMode(pic, col, mode);
  335.     G.RectFill(pic.rp, X, pic.height-Y-H, X+W-1, pic.height-Y-1)
  336. END ReplConst;
  337. PROCEDURE ReplConstC*(pic: Picture; f: Frame; col: INTEGER; X, Y, W, H, mode: INTEGER);
  338.     As ReplConst, but the rectangle is clipped against the frame boundary.
  339.         dx, dy: INTEGER;
  340. BEGIN
  341.     IF (W <= 0) OR (H <= 0) THEN RETURN END;
  342.     dx := f.X-X;
  343.     IF dx > 0 THEN X := f.X; DEC(W, dx) END;
  344.     dx := X+W-(f.X+f.W);
  345.     IF dx > 0 THEN DEC(W, dx) END;
  346.     dy := f.Y-Y;
  347.     IF dy > 0 THEN Y := f.Y; DEC(H, dy) END;
  348.     dy := Y+H-(f.Y+f.H);
  349.     IF dy > 0 THEN DEC(H, dy) END;
  350.     IF (W >0) & (H > 0) THEN ReplConst(pic,col, X, Y, W, H, mode) END
  351. END ReplConstC;
  352. PROCEDURE ReplPattern*(pic: Picture; col: INTEGER; pat: Pattern; X, Y, W, H, mode: INTEGER);
  353.     Fill the specified area with the pattern.
  354.     x, y, w, h, X1, Y1: INTEGER; p: Amiga.PatternInfoPtr;
  355.     wordStart:LONGINT;
  356.     bitOffset:INTEGER;
  357. BEGIN
  358.     SetDrawMode(pic, col, mode);
  359.     p := SYSTEM.VAL(Amiga.PatternInfoPtr, pat);
  360.     X1 := X+W; Y1 := Y+H; y := Y;
  361.     WHILE y < Y1 DO
  362.         IF y+p.h > Y1 THEN h := Y1-y ELSE h := p.h END;
  363.         x := X;
  364.         WHILE x < X1 DO
  365.             IF x+p.w > X1 THEN w := X1-x ELSE w := p.w END;
  366.             (*AdjustPointer(p.data+(p.h-h)*p.modulo,p.offset,wordStart,bitOffset);*)
  367.             wordStart:=p.data+(p.h-h)*p.modulo+p.offset DIV 8;
  368.             bitOffset:=SHORT(p.offset MOD 8);
  369.             IF ODD(wordStart) THEN
  370.                 DEC(wordStart);
  371.                 INC(bitOffset,8)
  372.             END;
  373.             G.BltTemplate(wordStart, bitOffset, p.modulo, pic.rp, x, pic.height-y-h, w, h);
  374.             x := x+p.w
  375.         END;
  376.         y := y+p.h
  377. END ReplPattern;
  378. PROCEDURE Min(x, y: INTEGER): INTEGER;
  379. BEGIN IF x < y THEN RETURN x ELSE RETURN y END
  380. END Min;
  381. PROCEDURE Max(x, y: INTEGER): INTEGER;
  382. BEGIN IF x > y THEN RETURN x ELSE RETURN y END
  383. END Max;
  384. PROCEDURE ReplPatternC*(pic:Picture; f: Frame; col: INTEGER; pat: Pattern; X, Y, W, H, X0, Y0, mode: INTEGER);
  385. (* Replicates a pattern pat within the block (X, Y, W, H), clipped against F. The pattern origin is X0, Y0; i.e. for each
  386.     completely visible occurrence of the pattern pat the following holds: ((x - X0) MOD w = 0) & ((y-Y0) MOD h = 0)
  387.     where (x, y) denotes the left and bottom corner, and (w, h) the size of the pattern. *)
  388.     rectangle: G.Rectangle; region, oldRegion: G.RegionPtr; p: Amiga.PatternInfoPtr;
  389.     dx, dy: INTEGER;
  390. BEGIN
  391.     IF (W <= 0) OR (H <= 0) THEN RETURN END;
  392.     region := G.NewRegion();
  393.     rectangle.minX := Max(f.X, X); rectangle.maxX := Min(f.X+f.W-1, X+W-1);
  394.     rectangle.minY := Max(pic.height-f.Y-f.H, pic.height-Y-H);
  395.     rectangle.maxY := Min(pic.height-f.Y-1, pic.height-Y-1);
  396.     IF G.OrRectRegion(region, SYSTEM.ADR(rectangle)) THEN
  397.         p := SYSTEM.VAL(Amiga.PatternInfoPtr, pat);
  398.         dx := (X-X0) MOD p.w; dy := (Y-Y0) MOD p.h;
  399.         oldRegion := L.InstallClipRegion(pic.layer, region);
  400.         ReplPattern(pic, col, pat, X-dx, Y-dy, W+dx, H+dy, mode);
  401.         region := L.InstallClipRegion(pic.layer, oldRegion);
  402.         G.DisposeRegion(region)
  403. END ReplPatternC;
  404. PROCEDURE Update*(P: Picture; X, Y , W, H: INTEGER);
  405. BEGIN
  406.     IF P.notify # NIL THEN P.notify(P, X, Y, W, H) END
  407. END Update;
  408. PROCEDURE DisplayBlock*(P: Picture; X, Y, W, H, DX, DY, mode: INTEGER);
  409.     I assume, this copies the picture to the screen.
  410. BEGIN
  411.     IF defaultPicture=NIL THEN
  412.         HALT(54)
  413.     ELSE
  414.         CopyBlock(P,defaultPicture,X,Y,W,H,DX,DY,mode)
  415. END DisplayBlock;
  416. PROCEDURE ReadInt(VAR R: Files.Rider; VAR i: INTEGER);
  417. VAR hi: SHORTINT; lo: CHAR; li: LONGINT;
  418. BEGIN
  419.     Files.Read(R, lo); Files.Read(R, hi); li:=ORD(lo) + 256*hi; i:=SHORT(li)
  420. END ReadInt;
  421. PROCEDURE WriteInt(VAR R: Files.Rider; i: INTEGER);
  422. BEGIN
  423.     Files.Write(R, CHR(i MOD 256)); Files.Write(R, CHR(i DIV 256 MOD 256))
  424. END WriteInt;
  425. PROCEDURE ReadPal(VAR R: Files.Rider; P: Picture; nofcol: LONGINT);
  426.     col:LONGINT;
  427. BEGIN
  428.     FOR col:=0 TO nofcol-1 DO
  429.         Files.Read(R, P.pal[col].r); Files.Read(R, P.pal[col].g); Files.Read(R, P.pal[col].b)
  430. END ReadPal;
  431. PROCEDURE WritePal(VAR R: Files.Rider; P: Picture; nofcol: LONGINT);
  432. VAR col: LONGINT;
  433. BEGIN
  434.     FOR col:=0 TO nofcol-1 DO
  435.         Files.Write(R, P.pal[col].r); Files.Write(R, P.pal[col].g); Files.Write(R, P.pal[col].b)
  436. END WritePal;
  437. PROCEDURE Define(P: Picture; width, height, depth: INTEGER);    (* set width, height, depth, next, pixmap *)
  438. BEGIN
  439.     IF (P.width # width) OR (P.height # height) OR (P.depth # depth) OR (P.layer=0) THEN
  440.         IF (width=0) OR (height=0) OR (depth=0) THEN HALT(50) END ;
  441.         IF P.layer # 0 THEN FreeLayer(P) ELSE Kernel.RegisterObject(P, Finalize) END ;
  442.         P.width:=width; P.height:=height; P.depth:=depth;
  443.         InitLayer(P);
  444.         IF P.layer=0 THEN HALT(40) END;
  445.         P.oldCol:=-1;
  446.         P.oldMode:=-1
  447. END Define;
  448. PROCEDURE ReadData(VAR R: Files.Rider; P: Picture; exp, map, rv: BOOLEAN);
  449.     Load run length encoded picture.
  450.     ch,ch1:CHAR;
  451.     k:INTEGER;
  452.     x,y,yoff:INTEGER;
  453.     width, height, depth: INTEGER;
  454.     m:ARRAY 256 OF CHAR;
  455.     r:G.RastPortPtr;
  456.     rptr:RastPortPtr;
  457.     bptr:BitMapPtr;
  458.     bpr: LONGINT;
  459.     planes: ARRAY 8 OF LONGINT;
  460.     (* faster Version of Dot, only for ReadData *)
  461.     PROCEDURE NDot(col, X, Y: INTEGER);
  462.     BEGIN
  463.         IF P.oldCol # col THEN P.oldCol := col; G.SetAPen(r, col+Amiga.ColorOffset) END;
  464.         G.WritePixel(r, X, P.height-Y-1)
  465.     END NDot;
  466.     PROCEDURE Unpack(p: LONGINT);
  467.         i: INTEGER;
  468.         pixel: INTEGER;
  469.     BEGIN
  470.         i:=8;
  471.         REPEAT
  472.             IF ODD(p) THEN pixel:=white ELSE pixel:=black END;
  473.             NDot(pixel,x,yoff-y-1); INC(x); p:=ASH(p,-1); DEC(i)
  474.         UNTIL (i=0) OR (x=width)
  475.     END Unpack;
  476.     (* new unpack writes data direct to the planes *)
  477.     PROCEDURE Unpack(p: INTEGER);
  478.         VAR
  479.             offset, count: LONGINT;
  480.             b: SYSTEM.BYTE;
  481.     BEGIN
  482.         b:=swap[p];
  483.         offset:=y*bpr+ASH(x,-3);
  484.         IF Amiga.OberonDepth<5 THEN
  485.             FOR count:=0 TO Amiga.OberonDepth-1 DO
  486.                 SYSTEM.PUT(planes[count]+offset, b)
  487.             END
  488.         ELSE
  489.             FOR count:=0 TO 3 DO
  490.                 SYSTEM.PUT(planes[count]+offset, b)
  491.             END;
  492.             FOR count:=4 TO Amiga.OberonDepth-1 DO
  493.                 SYSTEM.PUT(planes[count]+offset, 0X)
  494.             END
  495.         END;
  496.         INC(x, 8)
  497.     END Unpack;
  498. BEGIN
  499.     r:=P.rp; Dot(P, 0, 0, 0, replace); (* needed for new Dot *)
  500.     rptr:=SYSTEM.VAL(RastPortPtr, r);
  501.     depth:=P.depth;
  502.     height:=P.height;
  503.     width:=P.width;
  504.     yoff:=P.height-1;
  505.     IF depth=1 THEN (* install everythink for new Unpack *)
  506.         rptr:=SYSTEM.VAL(RastPortPtr, r);
  507.         bptr:=SYSTEM.VAL(BitMapPtr, rptr.bitMap);
  508.         bpr:=bptr.bytesPerRow;
  509.         FOR k:=0 TO Amiga.OberonDepth DO
  510.             planes[k]:=SYSTEM.VAL(LONGINT, bptr.planes[k])
  511.         END
  512.     END;
  513.     IF map THEN
  514.         (*WHILE k < 256 DO m[k] := CHR((k MOD 2)*15); INC(k) END ;
  515.         m[12] := CHR(15); m[13] := CHR(0); m[14] := CHR(15)*)
  516.         x:=SHORT(ASH(1,depth));m[0]:=0X;
  517.         FOR k:=1 TO 255 DO
  518.             m[k]:=CHR(k MOD x);
  519.             IF m[k]=0X THEN m[k]:=0FX END
  520.         END
  521.     END;
  522.     y:=0;
  523.     FOR y:=0 TO height-1 DO
  524.         x:=0;
  525.         WHILE x<width  DO
  526.             Files.Read(R,ch);
  527.             k:=ORD(ch);
  528.             IF k<128 THEN
  529.                 REPEAT
  530.                     Files.Read(R,ch);
  531.                     IF exp THEN
  532.                         ch1:=CHR(ORD(ch) MOD 16);
  533.                         ch:=CHR(ORD(ch) DIV 16);
  534.                         IF map THEN
  535.                             ch1:=m[ORD(ch1)];
  536.                             ch:=m[ORD(ch)]
  537.                         END;
  538.                         NDot(ORD(ch1),x,yoff-y);
  539.                         INC(x)
  540.                     ELSIF map THEN
  541.                         ch:=m[ORD(ch)]
  542.                     ELSIF rv THEN
  543.                         ch:=CHR(rev[ORD(ch) DIV 16]+rev[ORD(ch) MOD 16]*16)
  544.                     END;
  545.                     IF x<width THEN
  546.                         IF (depth=1) & ~map THEN
  547.                             Unpack(ORD(ch))
  548.                         ELSE
  549.                             NDot(ORD(ch),x,yoff-y);
  550.                             INC(x)
  551.                         END
  552.                     END ;
  553.                     DEC(k)
  554.                 UNTIL k<0
  555.             ELSE
  556.                 k:=257-k;
  557.                 Files.Read(R, ch);
  558.                 IF exp THEN
  559.                     ch1:=CHR(ORD(ch) MOD 16);
  560.                     ch:=CHR(ORD(ch) DIV 16);
  561.                     IF map THEN
  562.                         ch1:=m[ORD(ch1)];
  563.                         ch:=m[ORD(ch)]
  564.                     END
  565.                 ELSIF map THEN
  566.                     ch:=m[ORD(ch)]
  567.                 ELSIF rv THEN
  568.                     ch:=CHR(rev[ORD(ch) DIV 16]+rev[ORD(ch) MOD 16]*16)
  569.                 END ;
  570.                 REPEAT
  571.                     IF exp THEN
  572.                         NDot(ORD(ch1),x,yoff-y);
  573.                         INC(x)
  574.                     END;
  575.                     IF x < width THEN
  576.                         IF (depth=1) & ~map THEN
  577.                             Unpack(ORD(ch))
  578.                         ELSE
  579.                             NDot(ORD(ch),x,yoff-y);
  580.                             INC(x)
  581.                         END
  582.                     END;
  583.                     DEC(k)
  584.                 UNTIL k<1
  585.             END
  586.         END
  587.     END;
  588.     G.SetWriteMask(P.rp, 0)
  589. END ReadData;
  590. PROCEDURE Load*(P: Picture; F: Files.File; pos: LONGINT; VAR len: LONGINT);
  591.     Load a pictures which was identified as starting with a PictFileId.
  592.     expand,map:BOOLEAN;
  593.     R:Files.Rider;
  594.     width,height,depth:INTEGER;
  595. BEGIN
  596.     Files.Set(R,F,pos); ReadInt(R,width); ReadInt(R,height); ReadInt(R,depth);
  597.     ReadPal(R,P,ASH(1,depth)); (* RGB-Werte der Originalfarben laden *)
  598.     expand:=FALSE;
  599.     map:=FALSE;
  600.     IF depth=4 THEN (* Ceres color picture *)
  601.         expand:=TRUE;
  602.         map:=Amiga.OberonDepth#4;
  603.         depth:=Amiga.OberonDepth
  604.     ELSIF depth>Amiga.OberonDepth THEN
  605.         map:=TRUE;
  606.         depth:=Amiga.OberonDepth
  607.     END ;
  608.     (* IF (depth#Amiga.Depth) & (depth#1) THEN HALT(43) END; *)
  609.     Define(P,width,height,depth);
  610.     ReadData(R,P,expand,map,FALSE);
  611.     len:=Files.Pos(R)-pos
  612. END Load;
  613. PROCEDURE Store*(P: Picture; F: Files.File; pos: LONGINT; VAR len: LONGINT);
  614.     stores picture to run length encoded file F   (including tag)
  615.     a, b, x, y, width, height, depth, oridepth: INTEGER;
  616.     j: LONGINT;
  617.     h: CHAR;
  618.     buf: ARRAY 129 OF CHAR;
  619.     R: Files.Rider;
  620.     PROCEDURE Pack(): CHAR;
  621.         VAR i, j, p: INTEGER;
  622.     BEGIN
  623.         i:=8; j:=1; p:=0;
  624.         REPEAT
  625.             IF Get(P, x, P.height-y-1)#black THEN INC(p, j) END;
  626.             INC(x); j:=j*2; DEC(i)
  627.         UNTIL (i=0) OR (x=width);
  628.         RETURN CHR(p)
  629.     END Pack;
  630.     (* store pictures with 4 planes in Ceres 4 colors-format *)
  631.     PROCEDURE PackColor(): CHAR;
  632.         VAR ch, ch1: INTEGER;
  633.     BEGIN
  634.         ch:=Get(P, x, P.height-y-1)-Amiga.ColorOffset; INC(x);
  635.         ch1:=Get(P, x, P.height-y-1)-Amiga.ColorOffset; INC(x);
  636.         RETURN CHR(ch+ch1*16)
  637.     END PackColor;
  638. BEGIN
  639.     width:=P.width; height:=P.height; oridepth:=P.depth;
  640.     (* only store as 1, 4 or 8 Plane Pict *)
  641.     depth:=oridepth;
  642.     IF (oridepth=2) OR (oridepth=3) THEN depth:=4 END;
  643.     IF (oridepth>4) & (oridepth<7) THEN depth:=8 END;
  644.     Files.Set(R, F, pos); WriteInt(R, PictFileId);
  645.     WriteInt(R, width); WriteInt(R, height); WriteInt(R, depth);
  646.     WritePal(R, P, ASH(1, depth));
  647.     (* fill Colortabel with 0 *)
  648.     IF depth#oridepth THEN
  649.         FOR j:=1 TO (ASH(1, depth)-ASH(1, oridepth))*3 DO
  650.             Files.Write(R, CHR(0))
  651.         END
  652.     END;
  653.     y:=0;
  654.     WHILE height > 0 DO x:=0; a:=0;
  655.         j:=1; buf[0]:=0X;
  656.         IF depth=1 THEN h:=Pack()
  657.         ELSIF depth=4 THEN h:=PackColor()
  658.         ELSE h:=CHR(Get(P, x, P.height-y-1)); INC(x)
  659.         END ;
  660.         b:=1; buf[j]:=h;
  661.         WHILE x < width DO
  662.             IF depth=1 THEN h:=Pack()
  663.             ELSIF depth=4 THEN h:=PackColor()
  664.             ELSE h:=CHR(Get(P, x, P.height-y-1)); INC(x)
  665.             END;
  666.             IF ((b - a) < 127) & ((buf[0]=0X) OR ((h=buf[j]) & (j=1)) OR ((h # buf[j]) & (j  > 1))) THEN (* same run *)
  667.                 IF h # buf[j] THEN INC(SYSTEM.VAL(SHORTINT, buf[0])); INC(j); buf[j]:=h
  668.                 ELSE DEC(SYSTEM.VAL(SHORTINT, buf[0])) END
  669.             ELSE (* new run *)
  670.                 IF (buf[j]=h) & (b - a # 127) THEN DEC(SYSTEM.VAL(SHORTINT, buf[0])); Files.WriteBytes(R, buf, j); buf[0]:=0FFX
  671.                 ELSE Files.WriteBytes(R, buf, j + 1); buf[0]:=0X END ;
  672.                 j:=1; buf[j]:=h; a:=b
  673.             END ;
  674.             INC(b)
  675.         END ;
  676.         Files.WriteBytes(R, buf, j + 1);
  677.         DEC(height); INC(y)
  678.     END ;
  679.     len:=Files.Pos(R) - pos
  680. END Store;
  681. PROCEDURE Create*(P: Picture; width, height, depth: INTEGER);
  682.     Create a picture with the requested size. The main work is done
  683.     in Define. This only clears the picture area and the color
  684.     palette.
  685.     col: INTEGER;
  686. BEGIN
  687.     Define(P, width, height, depth);
  688.     ReplConst(P, black, 0, 0, P.width, P.height, replace);
  689.     FOR col:=0 TO 255 DO P.pal[col].r:=0X; P.pal[col].g:=0X; P.pal[col].b:=0X END
  690. END Create;
  691. PROCEDURE Open*(P: Picture; name: ARRAY OF CHAR);
  692.     Load a file into a picture.
  693.     F:Files.File;
  694.     R:Files.Rider;
  695.     len: LONGINT;
  696.     x, d: INTEGER;
  697.     dname: ARRAY 64 OF CHAR;
  698. BEGIN
  699.     F:=Files.Old(name);
  700.     IF F#NIL THEN
  701.         Files.Set(R,F,0);
  702.         x:=0;
  703.         ReadInt(R,x);
  704.         IF x=0 THEN (* MacPaint format *)
  705.             Define(P,576,720,1);
  706.             Files.Set(R,F,Files.Pos(R)+510);
  707.             ReadData(R,P,FALSE,FALSE,TRUE)
  708.         ELSIF x=PictFileId THEN
  709.             Load(P,F,2,len)
  710.         ELSIF x=07F7H THEN (* Skipping System3 File-Header *)
  711.             Files.ReadString(R, dname); Files.ReadInt(R, d); Files.ReadInt(R, d); Files.ReadInt(R, d); Files.ReadInt(R, d);
  712.             Files.ReadInt(R, x);
  713.             IF x=PictFileId THEN
  714.                 Load(P, F, Files.Pos(R), len)
  715.             ELSE
  716.                 O.Str("System3-File, Unknown format");O.Ln
  717.             END
  718.         ELSE
  719.             O.Str("Unknown format");O.Ln
  720.         END
  721.     ELSE
  722.         O.Str("Pictures.Open: "); O.Str(name); O.Str(" failed"); O.Ln;
  723.         Create(P,Amiga.Width*5 DIV 8 -20,Amiga.Height-80,Amiga.OberonDepth)
  724. END Open;
  725. PROCEDURE SetColor*(P:Picture; col,red,green,blue:INTEGER);
  726.     Change the RGB values of a palette entry.
  727. BEGIN
  728.     IF (col<nofCols) & (col>=0) THEN
  729.         P.pal[col].r:=CHR(red); P.pal[col].g:=CHR(green); P.pal[col].b:=CHR(blue)
  730. END SetColor;
  731. PROCEDURE GetColor*(P: Picture; col: INTEGER; VAR red, green, blue: INTEGER);
  732.     Retrieve the RGB values of a palette entry.
  733. BEGIN
  734.     IF (col<nofCols) & (col>=0) THEN
  735.         red:=ORD(P.pal[col].r); green:=ORD(P.pal[col].g); blue:=ORD(P.pal[col].b)
  736. END GetColor;
  737. PROCEDURE NewPattern*(VAR image: ARRAY OF SET; w, h: INTEGER): Pattern;
  738. (* Allocates a new pattern with width w and height h. The i-th pattern line from bottom (increasing y-value)
  739.     corresponds to the image entries (i+1)*lineLen .. (i+2)*lineLen-1, where lineLen = (w+31) DIV 32.
  740.     The set elements describe the pixels from left to right (increasing x-value). *)
  741. CONST header=4;
  742.         ch: CHAR; src, dest: LONGINT; byte, bytesPerRow, i, size: LONGINT;
  743.         pattern: Amiga.PatternInfoPtr; patNode: PatternNode;
  744. BEGIN
  745.     Amiga.Assert((0<w) & (w<=32) & (0<h),"Illegal pattern size");
  746.     NEW(pattern); pattern.w := SHORT(w); pattern.h := SHORT(h); pattern.modulo := 2*((w+15) DIV 16);
  747.     NEW(patNode); patNode.next := patternRoot; patternRoot := patNode;
  748.     patNode.p := pattern;    (* to insert pattern into global list for GC *)
  749.     size := pattern.modulo*h;
  750.     IF Amiga.ChipMemPool#0 THEN
  751.         pattern.data:=E.AllocPooled(Amiga.ChipMemPool, size)
  752.     ELSE
  753.         pattern.data := E.AllocMem(size, {E.memChip})
  754.     END;
  755.     pattern.offset:=0;
  756.     bytesPerRow := (w + 7) DIV 8;
  757.     src := SYSTEM.ADR(image)+header+3; dest := pattern.data+pattern.modulo*(h-1);
  758.     FOR i := 0 TO h-1 DO
  759.         FOR byte := 1 TO bytesPerRow DO
  760.             SYSTEM.GET(src, ch); SYSTEM.PUT(dest, Amiga.SwapBits[ORD(ch)]);
  761.             DEC(src); INC(dest)
  762.         END;
  763.         DEC(dest, bytesPerRow+pattern.modulo);
  764.         INC(src, bytesPerRow+4)
  765.     END;
  766.     RETURN SYSTEM.VAL(Pattern,pattern)
  767. END NewPattern;
  768. PROCEDURE Line*(pic:Picture; f:Frame; col, X0, Y0, X1, Y1, mode: INTEGER);
  769. (* Draws a line from (X0, Y0) to (X1, Y1) inclusive, clipped against F.  For all line points (x, y) the following holds
  770. always: (min(X0, X1) <= x) & (x <= max(X0, X1) & (min(Y0, Y0) <= y) & (y <= max(Y0, Y1). *)
  771.     rectangle: G.Rectangle;
  772.     region,oldRegion: G.RegionPtr;
  773. BEGIN
  774.     SetDrawMode(pic, col, mode);
  775.     region := G.NewRegion();
  776.     rectangle.minX := f.X; rectangle.maxX := f.X+f.W-1;
  777.     rectangle.minY := pic.height-f.Y-f.H; rectangle.maxY := rectangle.minY+f.H-1;
  778.     IF G.OrRectRegion(region, SYSTEM.ADR(rectangle)) THEN
  779.         oldRegion := L.InstallClipRegion(pic.layer, region);
  780.         G.Move(pic.rp,X0,pic.height-Y0-1);
  781.         G.Draw(pic.rp,X1,pic.height-Y1-1);
  782.         region := L.InstallClipRegion(pic.layer, oldRegion);
  783.         G.DisposeRegion(region)
  784. END Line;
  785. PROCEDURE Ellipse*(pic:Picture; f:Frame; col, X, Y, A, B, mode: INTEGER);
  786. (* Draws an ellipse with center (X, Y) and radii A and B, clipped against F. For all ellipse points (x, y)  the following holds
  787.     always: (X-A <= x) & (x < X+A) & (Y-B <= y) & (y < Y+B). When A = B the resulting ellipse has the same shape
  788.     as the corresponding circle with R = A. *)
  789.     rectangle: G.Rectangle;
  790.     region,oldRegion: G.RegionPtr;
  791. BEGIN
  792.     SetDrawMode(pic, col, mode);
  793.     region := G.NewRegion();
  794.     rectangle.minX := f.X; rectangle.maxX := f.X+f.W-1;
  795.     rectangle.minY := pic.height-f.Y-f.H; rectangle.maxY := rectangle.minY+f.H-1;
  796.     IF G.OrRectRegion(region, SYSTEM.ADR(rectangle)) THEN
  797.         oldRegion := L.InstallClipRegion(pic.layer, region);
  798.         G.DrawEllipse(pic.rp,X,pic.height-Y-1,A,B);
  799.         region :=L.InstallClipRegion(pic.layer, oldRegion);
  800.         G.DisposeRegion(region)
  801. END Ellipse;
  802. PROCEDURE Circle*(pic:Picture; f:Frame; col, X, Y, R, mode: INTEGER);
  803. (* Draws a circle with center (X, Y) and radius R, clipped against F. For all circle points (x, y)  the following holds always:
  804.     (X-R <= x) & (x < X+R) & (Y-R <= y) & (y < Y+R). *)
  805. BEGIN
  806.     Ellipse(pic,f,col,X,Y,R,R,mode)
  807. END Circle;
  808. PROCEDURE AmigaText*(P:Picture; font:G.TextFontPtr; VAR text: ARRAY OF CHAR; count, x, y, col, mode: INTEGER);
  809.     Print text with Amiga font
  810. BEGIN
  811.     SetDrawMode(P, col, mode);
  812.     G.Move(P.rp, x, P.height-y-1);
  813.     G.SetFont(P.rp, font);
  814.     G.Text(P.rp, text, count)
  815. END AmigaText;
  816. PROCEDURE Init;
  817.     im: ARRAY 17 OF SET;
  818.     k: INTEGER;
  819. BEGIN
  820.     defaultPicture:=NIL;
  821.     nofCols:=SHORT(ASH(1, Amiga.OberonDepth));
  822.     depthMask:=nofCols-1;
  823.     DrMode[replace]:=G.jam2;  DrMode[paint]:=G.jam1;  DrMode[invert]:=G.complement;        (*<<OJ*)
  824.     MinTerm[replace]:=0C0X;      (* dest := BC + B~C *)
  825.     MinTerm[paint]:=0E0X;         (* dest := BC + ~BC + B~C *)
  826.     MinTerm[invert]:=060X;        (* dest := B~C + ~BC *)
  827.     patternRoot:=NIL;
  828.     rev[0]:=0; rev[1]:=8; rev[2]:=4; rev[3]:=12;
  829.     rev[4]:=2; rev[5]:=10; rev[6]:=6; rev[7]:=14;
  830.     rev[8]:=1; rev[9]:=9; rev[10]:=5; rev[11]:=13;
  831.     rev[12]:=3; rev[13]:=11; rev[14]:=7; rev[15]:=15;
  832.     im[1]:={};
  833.     im[2]:={1..7,9..15}; im[3]:=im[2]; im[4]:=im[2]; im[5]:=im[2];
  834.     im[6]:=im[2]; im[7]:=im[2]; im[8]:=im[2]; im[9]:=im[1];
  835.     im[10]:=im[2]; im[11]:=im[2]; im[12]:=im[2]; im[13]:=im[2];
  836.     im[14]:=im[2]; im[15]:=im[2]; im[16]:=im[2];
  837.     dots:=NewPattern(im, 16, 16)
  838. END Init;
  839. BEGIN
  840.     Init
  841. END Pictures.
  842.